#! /usr/bin/perl

use lib::Test;
use tests::CreationTest;
### VSTF
### Very simple (automated) testing framework

### RUNTESTS:
### Startup script: Loads definition files and run the tests


# Containes the list of target tests for the whole batch
my @batch_tests = ();

## PROCESS COMMAND LINE PARAMETERS
## ===============================
# Parameters can be either switches or test names
# Switches are parameters of the form "-<triggername>"
# They can appear at any place on the command line
# Anything else is considered to be a test name
#
# Switches are processed inmediatly and trigger command flags
# Test names are added in order to a list for later processing

my $show_container = 0;
my $show_test_queue = 0;
foreach(@ARGV){
    if(/-(.*)/){
	$show_container = 1 if($1 eq "sc");
	$show_test_queue = 1 if($1 eq "sq");
    }else{
	push @batch_tests, $_;
    }
} 

foreach(@batch_tests){

# Hash shared by all tests
    my %container = ();
# Queue of remaining tests to be executed 
# Contains strings with the names of the tests
    my @testqueue = ();


## INITIALIZATION OF THE TEST QUEUE
## ================================
# For each test name given:
#  Add to the queue
#  Obtain dependencies and add to the queue
#  All dependencies of each test must appear before it
#
# Implementation notes:
# This is an exercise in implementing a simple recursive
# algorithm without the use of recursive functions.

# Auxiliary stack for the recursive process 
    my @stack;

    push @stack ,$_; # Target test is the first in the stack

# For all elements in the stack
#    Generate test name
#    Add to the queue
#    Evaluate the class definiton
#    Find all dependencies
#    Add the dependencies to the stack
    my $current = "";
    while(scalar(@stack) > 0){
	$current = pop @stack;

	#print "=========================\n";
	#print "---CURRENT:".$current."\n";


	my $testName = ucfirst($current)."Test";


	#print "---PUSHING:".$testName."\n";
	push @testqueue, $testName;
	# Evaluate the class definition
	eval "use tests::".$testName;


	# Initialize container
	# ------------------------
	# Open definition file for the test
	# Each line contains KEY VALUE
	# Add the pairs to the container
	my $filename = lc($current.".tst");
	if(-e $filename){
	    open TEST_DEF, "<".$filename;
	    while (<TEST_DEF>){
		chomp;
		my @key_val = split /=/;
		my $key = shift (@key_val);
		my $val = shift (@key_val);
		
		$key =~ s/^\s+|\s+$//g;
		$val =~ s/^\s+|\s+$//g;
		
		next if (substr($key, 0, 1) eq "#"); # Skip comments
		next if ($key eq ""); # Skip empty lines

		# If the value is a list, parse it
		if($val =~ /\((.*)\)/){ # Matches anything within parenthesis and extracts the contents of the parentheses to $1
		    my @listofvalues = split /\s*,\s*/, $1;
		    
		    # val becomes a reference to the list
		    $val = \@listofvalues;
		}
		
		$container{$key} = $val 
	    }
	}

	# Add all dependencies to the stack
	# Add dependencies to the stack
	my @dependencies = eval '@'.$testName."::DEPENDS_ON";

#	print "---DEPENDENCIES:".(join ",", @dependencies)."\n";

	push @stack, @dependencies;

#	print "---STACK BECOMES:".(join ",", @stack)."\n";
#	print "---QUEUE BECOMES:".(join ",", @testqueue)."\n";

    } 
# The queue must be reversed, dependencies must appear first
    @testqueue = reverse @testqueue;

# =====================================================
# INSPECT THE INITIAL STATUS OF THE CONTAINER AND QUEUE
# =====================================================

    if($show_test_queue){
# Inspect the test queue
	print "\n";
	print "TEST QUEUE\n";
	print "==========\n";
	foreach(@testqueue){
	    print;
	    print "\n";
	} # foreach(@testqueue)
    }

    if($show_container){
# Inspect the container
	print "\n";
	print "CONTAINER\n";
	print "=========\n";
	foreach(keys %container){
	    print;
	    print "->";
	    my $value = $container{$_};
	    
	    if(ref $container{$_} eq "ARRAY"){
		$value = "(".(join " || ", @{$value}).")";
	    }

	    print $value;
	    print "\n";
	} # foreach (keys in container)
    }

# =====================================================
# =====================================================
# BEGIN PROCESSING THE TESTS IN THE QUEUE
# =====================================================
# =====================================================

# To be used for efficienttly determine wheter a
# dependency test  has already been executed for
# the current target
    my %executedTests = ();

    foreach(@testqueue){
	my $testName = $_;

	if ($executedTests{$testName} == 1){
	    print "\n======================================================\n";
	    print "Skipping ".$testName." - Already run for this target\n";
	    print "======================================================\n";
	    next;
	}

	$executedTests{$testName} = 1;

	# Make a test object
	my $test = eval $testName."->create";
	if(!defined($test)){
	    print "**Error: required test ".$testName." not found**\n";
	    next;
	}

	# Set up the test
	$test->{CONTAINER} = \%container;
	
	# Run test
	print "\n";
	print "RUNNING TEST: ".$testName."\n";
	print "=============\n";
	$test->setup;
	$test->run;
	$test->teardown;

	# Assert variables
	%vars = $test->vars;
	@varnames = keys %vars;

	print "\n";
	print "FINAL REPORT:\n";
	print "=============\n";
	foreach my $varname (@varnames){
	    if($vars{$varname}){
		print "    OK:    ";
	    }else{
		print "--->ERROR: ";
	    }   
	    print $varname;
	    print "\n";
	} #foreach(test result variables)
    } # foreach(@testqueue)

} # foreach(batch target tests)
